Extract expected travel durations from Garmin BaseCamp GDB output (#585)
authorlintondf <lintondf@users.noreply.github.com>
Sun, 7 Jun 2020 22:19:10 +0000 (18:19 -0400)
committerGitHub <noreply@github.com>
Sun, 7 Jun 2020 22:19:10 +0000 (16:19 -0600)
* extract track segment expected travel durations from Garmin BaseCamp autorouted GDB exports and report as <rtept/src> elements in gpx output

* revised to use Garmin Format-Specific Data object to store durations

* generate at frozen test time

* include code review suggestions

* store Garmin BaseCamp autoroute waypoint travel durations in the <desc> elements of <rtept> waypoints; modify gpx ouptut to exclude autoroute generated rtept waypoints from initial waypoint list

* remove waypoint class lookup and replace tabs with spaces

* run astyle on gdb.cc

* turn off detailed GDB debugging

Co-authored-by: tsteven4 <13596209+tsteven4@users.noreply.github.com>
garmin_fs.h
gdb.cc
gpx.cc
reference/gdb-sample-v3-autoroute.gpx

index cd68fc1847f2a4bd7b98f48ba035dcf219af6204..26f25673c04fcce9e4de400449d6879674b5520f 100644 (file)
@@ -67,7 +67,8 @@ public:
   phone_nr2(0),
   fax_nr(0),
   postal_code(0),
-  email(0)
+  email(0),
+  duration(0)
 #ifdef GMSD_EXPERIMENTAL
   , subclass(0)
 #endif
@@ -89,6 +90,7 @@ public:
   unsigned int fax_nr:1;
   unsigned int postal_code:1;
   unsigned int email:1;
+  unsigned int duration:1;
 #ifdef GMSD_EXPERIMENTAL
   unsigned int subclass:1;
 #endif
@@ -116,6 +118,8 @@ public:
   QString fax_nr;                              /* fax number */
   QString postal_code; /* postal code */
   QString email;                               /* email address */
+  unsigned int duration; /* expected travel time to next route point, in seconds, only when auto-routed */
+
   garmin_ilink_t* ilinks{nullptr};
 #ifdef GMSD_EXPERIMENTAL
   char subclass[22]{};
@@ -163,6 +167,7 @@ public:
   GEN_GMSD_METHODS(wpt_class)
   GEN_GMSD_METHODS(display)
   GEN_GMSD_METHODS(category)
+  GEN_GMSD_METHODS(duration)
 
 #undef GEN_GMSD_METHODS
 
diff --git a/gdb.cc b/gdb.cc
index 9334cb986861d26494bf4328d216dc5f6dfa2b83..fac5e66c8bb23de4085bb217549aec308fff988a 100644 (file)
--- a/gdb.cc
+++ b/gdb.cc
@@ -20,7 +20,7 @@
        along with this program; if not, write to the Free Software
        Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
-  A format description obtained from reverse-engineering is at 
+  A format description obtained from reverse-engineering is at
   https://www.memotech.franken.de/FileFormats/Garmin_MPS_GDB_and_GFI_Format.pdf
 */
 
@@ -87,7 +87,7 @@ static char gdb_release_date[] = "$Date: 2011-04-14 01:30:01 $";
 static gbfile* fin, *fout, *ftmp;
 static int gdb_ver, gdb_category, gdb_via, gdb_roadbook;
 
-static QList<Waypoint *> wayptq_in, wayptq_out, wayptq_in_hidden;
+static QList<Waypoint*> wayptq_in, wayptq_out, wayptq_in_hidden;
 static short_handle short_h;
 
 static char* gdb_opt_category;
@@ -112,10 +112,10 @@ static int trk_ct;        /* informational: total number of tracks in/out */
 #define NOT_EMPTY(a) (a && *a)
 
 static void
-gdb_flush_waypt_queue(QList<Waypoint *>* Q)
+gdb_flush_waypt_queue(QList<Waypoint*>* Q)
 {
 
-  while(!Q->isEmpty()) {
+  while (!Q->isEmpty()) {
     const Waypoint* wpt = Q->takeFirst();
     if (wpt->extra_data) {
       // FIXME
@@ -177,13 +177,13 @@ disp_summary(const gbfile* f)
 
 #define FREAD_STR() gbfgetnativecstr(fin)
 
-// This is all very messy.  Some versions of GDB store strings as 
-// 8859-1 strings and others as UTF8.  This wrapper tries to hide 
+// This is all very messy.  Some versions of GDB store strings as
+// 8859-1 strings and others as UTF8.  This wrapper tries to hide
 // all that while (while keeping the character sets correct) and
 // not pushing that decision  down into gbfread.  This module is
 // still pretty messy and the points as to which fields are encode
 // which ways in which versions are not at all clear, leading to
-// encoding issues on read and leaks because of the differences 
+// encoding issues on read and leaks because of the differences
 // in calling conventions on who owns/destroys the result.
 
 #define FREAD_CSTR_AS_QSTR gbfgetcstr(fin)
@@ -194,12 +194,12 @@ static QString fread_cstr()
 {
   QString rv;
   char* s = gdb_fread_cstr(fin);
-  if (gdb_ver >= GDB_VER_UTF8) { 
+  if (gdb_ver >= GDB_VER_UTF8) {
     rv = QString::fromUtf8(s);
   } else {
     rv = QString::fromLatin1(s);
   }
-  
+
   xfree(s);
 
   return rv;
@@ -238,7 +238,7 @@ gdb_fread_strlist()
 }
 
 static Waypoint*
-gdb_find_wayptq(const QList<Waypoint *>* Q, const Waypoint* wpt, const char exact)
+gdb_find_wayptq(const QList<Waypoint*>* Q, const Waypoint* wpt, const char exact)
 {
   QString name = wpt->shortname;
   foreach (Waypoint* tmp, *Q) {
@@ -281,8 +281,8 @@ gdb_add_route_waypt(route_head* rte, Waypoint* ref, const int wpt_class)
        but probably from another data stream. Check coordinates!
     */
     double dist = radtometers(gcdist(
-      RAD(ref->latitude), RAD(ref->longitude),
-      RAD(tmp->latitude), RAD(tmp->longitude)));
+                                RAD(ref->latitude), RAD(ref->longitude),
+                                RAD(tmp->latitude), RAD(tmp->longitude)));
 
     if (fabs(dist) > 100) {
       warning(MYNAME ": Route point mismatch!\n");
@@ -303,10 +303,39 @@ gdb_add_route_waypt(route_head* rte, Waypoint* ref, const int wpt_class)
   return res;
 }
 
+QString gdb_to_ISO8601_duration(unsigned int seconds)
+{
+  if (seconds == 0u) {
+    return QString("PT0S");
+  }
+  unsigned int days = seconds / 86400u;
+  QString out = "P";
+  if (days != 0) {
+    out.append(QString("D%1").arg(days));
+    seconds -= 86400u * days;
+  }
+  out.append(QString("T"));
+  unsigned int hours = seconds / 3600u;
+  if (hours != 0) {
+    out.append(QString("%1H").arg(hours));
+    seconds -= 3600u * hours;
+  }
+  unsigned int minutes = seconds / 60u;
+  if (minutes != 0) {
+    out.append(QString("%1M").arg(minutes));
+    seconds -= 60u * minutes;
+  }
+  if (seconds != 0) {
+    out.append(QString("%1S").arg(seconds));
+  }
+  return out;
+}
+
 /*******************************************************************************/
 /* TOOLS AND MACROS FOR THE WRITER */
 /*-----------------------------------------------------------------------------*/
-static void FWRITE_CSTR(const QString& a)  {
+static void FWRITE_CSTR(const QString& a)
+{
   if (a.isEmpty()) {
     gbfputc(0, fout);
     return;
@@ -478,9 +507,9 @@ read_waypoint(gt_waypt_classes_e* waypt_class_out)
   res->notes = fread_cstr();
 #if GDB_DEBUG
   DBG(GDB_DBG_WPTe, !res->notes.isNull())
-    printf(MYNAME "-wpt \"%s\" (%d): notes = %s\n",
-           qPrintable(res->shortname), wpt_class,
-           qPrintable(QString(res->notes).replace("\r\n", ", ")));
+  printf(MYNAME "-wpt \"%s\" (%d): notes = %s\n",
+         qPrintable(res->shortname), wpt_class,
+         qPrintable(QString(res->notes).replace("\r\n", ", ")));
 #endif
   if (FREAD_C == 1) {
     WAYPT_SET(res, proximity, FREAD_DBL);
@@ -492,7 +521,7 @@ read_waypoint(gt_waypt_classes_e* waypt_class_out)
   }
   int display = FREAD_i32;
 #if GDB_DEBUG
-  DBG(GDB_DBG_WPTe, i)
+  DBG(GDB_DBG_WPTe, 1)
   printf(MYNAME "-wpt \"%s\" (%d): display = %d\n",
          qPrintable(res->shortname), wpt_class, display);
 #endif
@@ -562,8 +591,22 @@ read_waypoint(gt_waypt_classes_e* waypt_class_out)
 
     garmin_fs_t::set_addr(gmsd, fread_cstr());
 
-    FREAD(buf, 5);                             /* instruction depended */
+    FREAD(buf, 1);
+    unsigned int duration = gbfgetuint32(fin);
+
     res->description = FREAD_CSTR_AS_QSTR;     /* instruction */
+    if (wpt_class == gt_waypt_class_map_intersection || wpt_class == gt_waypt_class_map_line) {
+      garmin_fs_t::set_duration(gmsd, duration);
+      if (res->description.isEmpty()) {  //
+        res->description = res->shortname;
+      }
+      res->notes = QString("[%1]").arg(gdb_to_ISO8601_duration(duration));
+#if GDB_DEBUG
+      DBG(GDB_DBG_WPTe, 1)
+      printf(MYNAME "-wpt \"%s\" (%d): duration = %u\n",
+             qPrintable(res->shortname), wpt_class, duration);
+#endif
+    }
     int url_ct = FREAD_i32;
     for (int i = url_ct; (i); i--) {
       QString str = FREAD_CSTR_AS_QSTR;
@@ -634,7 +677,7 @@ read_waypoint(gt_waypt_classes_e* waypt_class_out)
 #endif
   QString str;
   if (!(str = garmin_fs_t::get_cc(gmsd, nullptr)).isEmpty()) {
-    if (! (garmin_fs_t::has_country(gmsd))) {
+    if (!(garmin_fs_t::has_country(gmsd))) {
       garmin_fs_t::set_country(gmsd, gt_get_icao_country(str));
     }
   }
@@ -856,9 +899,9 @@ read_route()
 #if GDB_DEBUG
       DBG(GDB_DBG_RTE, 1)
       printf(MYNAME "-rte_pt: autoroute info: route style %d, calculation type %d, vehicle type %d, road selection %d\n"
-                    "                            driving speeds (kph) %.0f, %.0f, %.0f, %.0f, %.0f\n",
-           route_style, calc_type, vehicle_type, road_selection,
-           driving_speed[0], driving_speed[1], driving_speed[2], driving_speed[3], driving_speed[4]);
+             "                            driving speeds (kph) %.0f, %.0f, %.0f, %.0f, %.0f\n",
+             route_style, calc_type, vehicle_type, road_selection,
+             driving_speed[0], driving_speed[1], driving_speed[2], driving_speed[3], driving_speed[4]);
 #else
       Q_UNUSED(route_style);
       Q_UNUSED(calc_type);
@@ -1280,7 +1323,7 @@ write_waypoint(
       ld = l.url_;
     }
     QString descr = (wpt_class < gt_waypt_class_map_point) ?
-                      ld : wpt->description;
+                    ld : wpt->description;
     if ((descr != nullptr) && (wpt_class >= gt_waypt_class_map_point) && \
         descr == CSTRc(wpt->shortname)) {
       descr.clear();
@@ -1322,7 +1365,7 @@ write_waypoint(
 #endif
 
     FWRITE_i32(wpt->urls.size());
-    foreach(UrlLink l, wpt->urls) {
+    foreach (UrlLink l, wpt->urls) {
       FWRITE_CSTR(l.url_);
     }
   }
@@ -1674,7 +1717,7 @@ write_track_cb(const route_head* trk)
     return;
   }
 
-  QString name; 
+  QString name;
   if (trk->rte_name.isNull()) {
     name = mkshort(short_h, QString::asprintf("Track%04d", trk->rte_num));
   } else {
diff --git a/gpx.cc b/gpx.cc
index 2fc109fffacfbeafab3352d4c08baf615549d20a..cd705917759dd897d69768d5ce1d024ebb378ddc 100644 (file)
--- a/gpx.cc
+++ b/gpx.cc
@@ -1621,7 +1621,11 @@ GpxFormat::write()
 
   gpx_reset_short_handle();
   auto gpx_waypt_pr_lambda = [this](const Waypoint* waypointp)->void {
-    gpx_waypt_pr(waypointp);
+       auto* gmsd = garmin_fs_t::find(waypointp); /* gARmIN sPECIAL dATA */
+       auto wc = garmin_fs_t::get_wpt_class(gmsd, 0);
+       if (wc != gt_waypt_class_map_intersection && wc != gt_waypt_class_map_line) {
+               gpx_waypt_pr(waypointp);
+       }
   };
   waypt_disp_all(gpx_waypt_pr_lambda);
   gpx_reset_short_handle();
index 4cea7a6362ec7e446642d030f7293c701745ea54..c5310a076049602ff4db2c5aac2f46226cb00120 100644 (file)
@@ -2,34 +2,6 @@
 <gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
   <time>1970-01-01T00:00:00Z</time>
   <bounds minlat="44.521450996" minlon="-68.208982944" maxlat="44.522766536" maxlon="-68.204090595"/>
-  <wpt lat="44.522766452" lon="-68.208928211">
-    <ele>37.273</ele>
-    <name>0001</name>
-    <cmt>Get on Manor Ln and drive south</cmt>
-    <desc>Get on Manor Ln and drive south</desc>
-    <sym>Waypoint</sym>
-  </wpt>
-  <wpt lat="44.522588253" lon="-68.208982944">
-    <ele>37.160</ele>
-    <name>0002</name>
-    <cmt>Turn left onto Us1</cmt>
-    <desc>Turn left onto Us1</desc>
-    <sym>Waypoint</sym>
-  </wpt>
-  <wpt lat="44.521901608" lon="-68.204090595">
-    <ele>40.863</ele>
-    <name>0003</name>
-    <cmt>Turn right onto Miramar Ave</cmt>
-    <desc>Turn right onto Miramar Ave</desc>
-    <sym>Waypoint</sym>
-  </wpt>
-  <wpt lat="44.521506736" lon="-68.204822838">
-    <ele>40.180</ele>
-    <name>0004</name>
-    <cmt>0004</cmt>
-    <desc>0004</desc>
-    <sym>Waypoint</sym>
-  </wpt>
   <wpt lat="44.522766536" lon="-68.208928127">
     <time>2020-05-22T12:02:08Z</time>
     <name>7 Manor Ln</name>
@@ -67,28 +39,28 @@ Sullivan Twn, ME, 04664, USA</desc>
       <ele>37.273</ele>
       <name>0001</name>
       <cmt>Get on Manor Ln and drive south</cmt>
-      <desc>Get on Manor Ln and drive south</desc>
+      <desc>[PT2S]</desc>
       <sym>Waypoint</sym>
     </rtept>
     <rtept lat="44.522588253" lon="-68.208982944">
       <ele>37.160</ele>
       <name>0002</name>
       <cmt>Turn left onto Us1</cmt>
-      <desc>Turn left onto Us1</desc>
+      <desc>[PT1M27S]</desc>
       <sym>Waypoint</sym>
     </rtept>
     <rtept lat="44.521901608" lon="-68.204090595">
       <ele>40.863</ele>
       <name>0003</name>
       <cmt>Turn right onto Miramar Ave</cmt>
-      <desc>Turn right onto Miramar Ave</desc>
+      <desc>[PT54S]</desc>
       <sym>Waypoint</sym>
     </rtept>
     <rtept lat="44.521506736" lon="-68.204822838">
       <ele>40.180</ele>
       <name>0004</name>
       <cmt>0004</cmt>
-      <desc>0004</desc>
+      <desc>[PT0S]</desc>
       <sym>Waypoint</sym>
     </rtept>
     <rtept lat="44.521450996" lon="-68.204820156">